package com.xzbd.springmongo.common.core;

import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;


@NoRepositoryBean
public interface BaseRepository<T extends BaseDocument, ID extends Serializable>
        extends PagingAndSortingRepository<T, ID> {

    public default Long count(MongoTemplate mongoTemplate, Query query,
                              Class<T> documentClass) {
        return mongoTemplate.count(query, documentClass);
    }

    public default Page<T> findAll(MongoTemplate mongoTemplate,
                                   Pageable pageable, Query query, Class<T> documentClass) {

        if (pageable.getSort() != null) {
            Iterator<Sort.Order> orders = pageable.getSort().iterator();
            while (orders.hasNext()) {
                Sort.Order order = orders.next();
                Sort sort = Sort.by(order);
                query.with(sort);
            }
        }
        long total = mongoTemplate.count(query, documentClass);
        if (total == 0) {
            return new PageImpl<T>(Collections.<T>emptyList(), pageable, total);
        }
        int totalPages = (int) (total + pageable.getPageSize() - 1)
                / pageable.getPageSize();
        if (pageable.getPageNumber() > (totalPages - 1)) {
            pageable = PageRequest.of(totalPages - 1, pageable.getPageSize(),
                    pageable.getSort());
        }
        query.skip(pageable.getOffset()).limit(pageable.getPageSize());
        List<T> subjectList = mongoTemplate.find(query, documentClass);
        return new PageImpl<T>(subjectList, pageable, total);
    }

    public default List<T> findAll(MongoTemplate mongoTemplate, Query query,
                                   Class<T> documentClass) {
        return mongoTemplate.find(query, documentClass);
    }

    public default T findOne(MongoTemplate mongoTemplate, Query query,
                             Class<T> documentClass, String collectionName) {
        return mongoTemplate.findOne(query, documentClass, collectionName);
    }

}